import DomUtil from '../src/utils/dom.js';

const CONSTRANTS = {
    TYPER_STATUS_TYPING: 'TYPING',
    TYPER_STATUS_STOPPED: 'STOPPED',
    TYPER_STATUS_TYPED: 'TYPED',
    TYPER_STATUS_WAITING: 'WAITING',
    TYPER_COMMAND_PRINT: 'PRINT'
};

const scopedStyles = `
    
`;

class Typer {

    constructor ({
        element,
        context = { pinyin: '', text: '' },
        splitWith = '&space&',
        outputAreaClass = '',
        inputAreaClass = '',
        cursorClass = '',
        printDelay = () => Math.random() * 200 + 100,
        queueDelay = 100
    }) {

        this.element = element;
        this.splitWith = splitWith;
        this.context = context;
        this.outputAreaClass = outputAreaClass;
        this.inputAreaClass = inputAreaClass;
        this.cursorClass = cursorClass;
        this.printDelay = printDelay;
        this.queueDelay = queueDelay;
        
        this._status = CONSTRANTS.TYPER_STATUS_WAITING;
        this._queue = [];

        this.render();
    }

    render () {
        if (!DomUtil.isDom(this.element)) {
            console.error(this.element, ' is not a valid DOM object.');
        }
        this.element.innerHTML = '';
        const $outputArea = document.createElement('span');
        $outputArea.setAttribute('class', 'typer-output-area ' + this.outputAreaClass);
        const $inputArea = document.createElement('span');
        $inputArea.setAttribute('class', 'typer-input-area ' + this.inputAreaClass);
        const $cursor = document.createElement('span');
        $cursor.setAttribute('class', 'typer-cursor ' + this.cursorClass);

        this.element.appendChild($outputArea);
        this.element.appendChild($inputArea);
        this.element.appendChild($cursor);

        this._$outputArea = $outputArea;
        this._$inputArea = $inputArea;
        this._$cursor = $cursor;
    }

    start (callback = () => {}) {
        const pinyinList = this.context.pinyin.split(this.splitWith);
        const textList = this.context.text.split(this.splitWith);

        var list = pinyinList.map((item, i) => { return { index: i, pinyin: item, text: textList[i] }; });

        const queue = list.reduce((prev, item) => [...prev, {
            command: CONSTRANTS.TYPER_COMMAND_PRINT,
            text: item.text,
            pinyin: item.pinyin,
            delay: this.printDelay()
        }], []);

        this._queue = [
            ...this._queue, 
            ...queue
        ];

        this.execQueue(callback);
    }

    execQueue(callback = () => {}) {
        if (this._queue.length === 0) {
            this._status = CONSTRANTS.TYPER_STATUS_STOPPED;
            return callback();
        }
        const exec = this._queue.shift();
        switch (exec.command) {
            case CONSTRANTS.TYPER_COMMAND_PRINT: {
                this.print(exec, callback);
            } break;
        }
    }

    print (exec = {}, callback = () => {}) {

        if (this._status === CONSTRANTS.TYPER_STATUS_STOPPED) {
            return callback();
        }
        
        if (this._status === CONSTRANTS.TYPER_STATUS_TYPING) {
            return setTimeout(() => {
                _print(exec, callback)
            }, this.queueDelay);
        }

        this._status = CONSTRANTS.TYPER_STATUS_TYPING;
        const { text, pinyin, delay } = exec;
        const currentText = this._$outputArea.innerText;

        this.printWord({
            pinyin,
            delay,
            callback: () => {
                this._$outputArea.innerText = currentText + text;
                this._$inputArea.innerText = '';
                this._status = CONSTRANTS.TYPER_STATUS_TYPED;
                this.execQueue(callback);
            }
        });
    }

    printWord ({
        pinyin = '',
        delay = 0,
        callback = () => {}
    }) {
        const arr = pinyin.split('');
        const interval = setInterval(() => {
            if (interval && arr.length > 0) {
                this._$inputArea.appendChild(document.createTextNode(arr.shift()));
            } else if (interval) {
                clearInterval(interval);
                callback();
            }
        }, delay);
    }
}

export default Typer;
